package java8;

import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * @auther hanchao
 * @date 2017/3/7 16:58
 */
public class StreamConcurrent {
    public static void main(String[] args){
        System.out.println("Sequential sum done in:" + measureSumPerf(ParallelStreams::iterativeSum,10_000_000) + " msecs");

        System.out.println("Sequential sum done in:" + measureSumPerf(ParallelStreams::sequentialSum, 10_000_000) + " msecs");

        System.out.println("Sequential sum done in:" + measureSumPerf(ParallelStreams::rangedSum, 10_000_000) + " msecs");
        System.out.println("Sequential sum done in:" + measureSumPerf(ParallelStreams::parallelRangedSum, 10_000_000) + " msecs");
    }

    public static long measureSumPerf(Function<Long, Long> adder, long n) {
        long fastest = Long.MAX_VALUE;
        for (int i = 0; i < 1; i++) {
            long start = System.nanoTime();
            long sum = adder.apply(n);
            long duration = (System.nanoTime() - start) / 1_000_000;
            if (duration < fastest) fastest = duration;
        }
        return fastest;
    }

    static class ParallelStreams {
        // iterate生成了装箱对象，所以会特别慢
        //iterate很难分割成能够独立执行的小块
        public static long sequentialSum(long n) {
            return Stream.iterate(1L, i->i+1)
                    .limit(n)
                    .reduce(0L, Long::sum);
        }

        public static long iterativeSum(long n) {
            long result = 0;
            for (long i = 1L; i <= n; i++) {
                result += i;
            }
            return result;
        }

        public static long parallelSum(long n) {
            return Stream.iterate(1L, i->i+1)
                    .limit(n)
                    .parallel()// sequential顺序流
                    .reduce(0L, Long::sum);
        }


        public static long rangedSum(long n) {
            return LongStream.rangeClosed(1, n)
                    .reduce(0L, Long::sum);
        }

        public static long parallelRangedSum(long n) {
            return LongStream.rangeClosed(1, n)
                    .parallel()
                    .reduce(0L, Long::sum);
        }
    }
}
